import 'dart:async';
import 'dart:io';

import 'cache_info_repository.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:synchronized/synchronized.dart';

import '../constants/constants.dart';
import 'cache_methods.dart';
import 'task_provider.dart';

class SqfliteHelper extends CacheInfoRepository
    with CacheInfoRepositoryHelperMethods {
  final lock = Lock(reentrant: true);
  Database? db;
  String? _path;

  SqfliteHelper._();

  static final SqfliteHelper _instance = SqfliteHelper._();

  static SqfliteHelper get instance {
    return _instance;
  }

  SqfliteHelper();

  ///
  /// 打开数据库
  ///
  @override
  Future<bool> open() async {
    if (!shouldOpenOnNewConnection()) {
      return openCompleter!.future;
    }
    final path = await _getPath();
    await File(path).parent.create(recursive: true);
    try {
      db = await openDatabase(
        path,
        // options: OpenDatabaseOptions(
        version: kVersion1,
        onCreate: (db, version) async {
          await TaskProvider.createTaskTable(db);
        },
        onUpgrade: (db, oldVersion, newVersion) async {
          if (oldVersion < kVersion1) {
            await TaskProvider.createTaskTable(db);
          }
        },
        // ),
      );
      return opened();
    } catch (e) {
      print('Failed to open database: $e');
      return false;
    }
  }

  Future<Database?> get ready async => db ??= await lock.synchronized(() async {
        if (db == null) {
          await open();
        }
        return db;
      });

  Future<String> fixPath(String dbName) async => _getPath();

  Future<String> _getPath() async {
    Directory directory;
    if (_path != null) {
      directory = File(_path!).parent;
    } else {
      directory = await getApplicationSupportDirectory();
    }
    await directory.create(recursive: true);
    if (_path == null || !_path!.endsWith('.db')) {
      _path = join(directory.path, dbName);
    }
    return _path!;
  }

  ///
  /// 关闭数据库
  ///
  @override
  Future<bool> close() async {
    if (!shouldClose()) return false;
    await db!.close();
    return true;
  }

  ///
  /// 删除数据库
  ///
  Future deleteDb() async {
    await databaseFactory.deleteDatabase(await fixPath(dbName));
  }

  @override
  Future<void> deleteDataFile() async {
    return databaseFactory.deleteDatabase(await fixPath(dbName));
  }

  @override
  Future<bool> exists() async {
    final path = await _getPath();
    return File(path).exists();
  }
}
